home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / networking / cisco / gdpd19jan91.shar / gdpd.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-08-07  |  19.5 KB  |  917 lines

  1. /*
  2.  * Gateway Discovery Protocol daemon suitable for using on Un*x systems.
  3.  *
  4.  * September 1989, Greg Satz
  5.  *
  6.  * Copyright (c) 1989 by cisco Systems, Inc.
  7.  * All rights reserved.
  8.  */
  9.  
  10. #include <sys/types.h>
  11. #include <sys/socket.h>
  12. #include <sys/ioctl.h>
  13. #include <sys/file.h>
  14. #include <sys/mbuf.h>
  15.  
  16. #include <net/if.h>
  17. #include <net/route.h>
  18. #include <netinet/in.h>
  19. #ifndef pyr
  20. #include <netinet/if_ether.h>
  21. #else
  22. #include <net/if_ether.h>
  23. #endif
  24.  
  25. #include <stdio.h>
  26. #include <signal.h>
  27. #include <errno.h>
  28. #include <netdb.h>
  29. #include <syslog.h>
  30. #include <nlist.h>
  31.  
  32. /*
  33.  * Gateway Discovery Protocol definitions
  34.  */
  35.  
  36. #define    GDP_VERSION    1
  37.  
  38. /*
  39.  * Operations
  40.  */
  41.  
  42. #define    GDP_REPORT    1
  43. #define    GDP_QUERY    2
  44.  
  45. /*
  46.  * GDP listener port
  47.  */
  48.  
  49. #define    GDP_PORT    1997
  50.  
  51. /*
  52.  * GDP packet format
  53.  */
  54.  
  55. struct gdppkt {
  56.     unsigned char version;
  57.     unsigned char code;
  58.     unsigned char count;
  59.     unsigned char reserved;
  60.     struct addrgrp {
  61.     struct in_addr ip;
  62.     unsigned short priority;
  63.     unsigned short holdtime;
  64.     } addrs[1];
  65. };
  66.  
  67. #define    ALARM_INTERVAL        1
  68.  
  69. #define    KERNEL        "/vmunix"
  70. #define    MEM        "/dev/kmem"
  71.  
  72. struct nlist nl[] = {
  73. #define    X_ARPTAB    0
  74.     { "_arptab" },
  75. #define    X_ARPTAB_SIZE    1
  76.     { "_arptab_size" },
  77. #define    N_RTHOST    2
  78.     { "_rthost" },
  79. #define    N_RTNET        3
  80.     { "_rtnet" },
  81. #define    N_RTHASHSIZE    4
  82.     { "_rthashsize" },
  83.     { "" },
  84. };
  85.  
  86. struct iface {
  87.     char name[IFNAMSIZ];
  88.     short flags;
  89.     struct in_addr ipaddress;
  90.     struct in_addr ipmask;
  91.     struct in_addr ipbroadcast;
  92.     struct iface *next;
  93. } *iflist;
  94.  
  95. struct neighbor {
  96.     struct in_addr ip;
  97.     unsigned short priority;
  98.     unsigned short holdtime;
  99.     struct neighbor *next;
  100. };
  101.  
  102. struct neighbor *rcvd_neighbors;
  103. struct neighbor *sent_neighbors;
  104.  
  105. struct neighbor *default_neighbor;
  106.  
  107. #define    DEFAULT_PRIORITY    100
  108. #define    DEFAULT_HOLDTIME    15
  109.  
  110. int debug;                /* debugging flag */
  111. int flush;                /* flush routing table flag */
  112. int logging;                /* syslog logging flag */
  113. int hold_time;                /* tell others how often to hold */
  114. int metric;                /* how do we run */
  115. int priority;                /* what priority do we advertise */
  116. int query_time;                /* how often to send queries */
  117. int query;
  118. int report_time;            /* how often to send reports */
  119. int report;
  120. int round_robin;            /* how often to cycle parallel gws */
  121. int round;
  122.  
  123. int s;
  124. struct sockaddr_in from;
  125. int fromlen;
  126. struct hostent *hp;
  127. struct servent *sp;
  128. unsigned char buf[BUFSIZ];
  129.  
  130. int timer();
  131.  
  132. /*
  133.  * main
  134.  * Perform GDP processing depending on what we were told
  135.  */
  136.  
  137. main (argc, argv)
  138.     int argc;
  139.     char *argv;
  140. {
  141.     int c, on = 1;
  142.     struct gdppkt *gdp;
  143.     struct addrgrp ag;
  144.     struct in_addr bip;
  145.     int oldmask;
  146.     extern char *optarg;
  147.     extern int optind;
  148.     extern int errno;
  149.  
  150.     debug = 0;
  151.     flush = 0;
  152.     logging = 0;
  153.     metric = 1;                /* default to one hop */
  154.     priority = DEFAULT_PRIORITY;
  155.     hold_time = DEFAULT_HOLDTIME;
  156.     query_time = 0;
  157.     report_time = 0;
  158.     round_robin = 0;
  159.     iflist = NULL;
  160.     rcvd_neighbors = NULL;
  161.     sent_neighbors = NULL;
  162.     default_neighbor = NULL;
  163.     bip.s_addr = 0L;
  164. #ifdef LOG_DAEMON
  165.     openlog("gdpd", LOG_PID, LOG_DAEMON);
  166. #else
  167.     openlog("gdpd", LOG_PID);
  168. #endif
  169.     while ((c = getopt(argc, argv, "dfh:lm:p:q:r:t:")) != EOF)
  170.     switch (c) {
  171.     case 'd':            /* debug */
  172.         debug = 1;
  173.         break;
  174.     case 'f':            /* flush  */
  175.         flush = 1;
  176.         break;
  177.     case 'h':            /* hold time */
  178.         hold_time = atoi(optarg);
  179.         if (hold_time < 0) {
  180.         fprintf(stderr, "%s: illegal hold time value - %d",
  181.             argv[0], hold_time);
  182.         exit(1);
  183.         }
  184.         break;
  185.     case 'l':            /* logging */
  186.         logging = 1;
  187.         break;
  188.     case 'm':            /* metric */
  189.         metric = atoi(optarg);
  190.         if (metric < 0) {
  191.         fprintf(stderr, "%s: illegal metric value - %d",
  192.             argv[0], metric);
  193.         exit(1);
  194.         }
  195.         break;
  196.     case 'p':            /* priority */
  197.         priority = atoi(optarg);
  198.         if (priority < 0) {
  199.         fprintf(stderr, "%s: illegal priority value - %d",
  200.             argv[0], priority);
  201.         exit(1);
  202.         }
  203.         break;
  204.     case 'q':            /* query */
  205.         query_time = atoi(optarg);
  206.         if (query_time < 0) {
  207.         fprintf(stderr, "%s: illegal querying value - %d",
  208.             argv[0], query_time);
  209.         exit(1);
  210.         }
  211.         break;
  212.     case 'r':            /* report */
  213.         report_time = atoi(optarg);
  214.         if (report_time < 0) {
  215.         fprintf(stderr, "%s: illegal reporting value - %d",
  216.             argv[0], report_time);
  217.         exit(1);
  218.         }
  219.         break;
  220.     case 't':            /* time */
  221.         round_robin = atoi(optarg);
  222.         if (round_robin < 0) {
  223.         fprintf(stderr, "%s: illegal round robin value - %d",
  224.             argv[0], round_robin);
  225.         exit(1);
  226.         }
  227.         round_robin *= 60;        /* make seconds */
  228.         break;
  229.     default:
  230.         fprintf(stderr, "%s: illegal switch -%s", argv[0], optarg);
  231.         exit(1);
  232.     }
  233.  
  234.     if (query_time != 0 && report_time != 0) {
  235.     fprintf(stderr, "%s: cannot report and query simultaneously.\n",
  236.         argv[0]);
  237.     exit(1);
  238.     }
  239.     bzero(&ag, sizeof(struct addrgrp));
  240.     while (argc != optind) {
  241.     ag.ip.s_addr = inet_addr(argv[optind]);
  242.     if (ag.ip.s_addr == -1) {
  243.         hp = gethostbyname(argv[optind]);
  244.         if (hp == NULL) {
  245.         fprintf(stderr, "%s: %s: unknown host\n", argv[0],
  246.             argv[optind]);
  247.         exit(1);
  248.         }
  249.         bcopy(hp->h_addr, &ag.ip, sizeof(ag.ip));
  250.     }
  251.     enter_neighbor(&sent_neighbors, &ag);
  252.     optind++;
  253.     }
  254.     query = query_time;
  255.     report = report_time;
  256.     round = round_robin;
  257.     if (metric == 0 || flush) {
  258.     nlist(KERNEL, nl);
  259.     if (nl[X_ARPTAB].n_value == 0) {
  260.         fprintf(stderr, "%s: %s: bad namelist\n", argv[0], KERNEL);
  261.         exit(1);
  262.     }
  263.     if (nl[X_ARPTAB_SIZE].n_value == 0) {
  264.         fprintf(stderr, "%s: %s: bad namelist\n", argv[0], KERNEL);
  265.         exit(1);
  266.     }
  267.     if (nl[N_RTHOST].n_value == 0) {
  268.         fprintf(stderr, "%s: %s: bad namelist\n", argv[0], KERNEL);
  269.         exit(1);
  270.     }
  271.     if (nl[N_RTNET].n_value == 0) {
  272.         fprintf(stderr, "%s: %s: bad namelist\n", argv[0], KERNEL);
  273.         exit(1);
  274.     }
  275.     if (nl[N_RTHASHSIZE].n_value == 0) {
  276.         fprintf(stderr, "%s: %s: bad namelist\n", argv[0], KERNEL);
  277.         exit(1);
  278.     }
  279.     }
  280.     if (debug)
  281.     syslog(LOG_DEBUG, "server starting");
  282.  
  283.     if (!debug) {
  284.     if (fork())
  285.         exit(0);
  286.     for (c = 0; c < getdtablesize(); c++)
  287.         (void) close(c);
  288.     (void) open("/", O_RDONLY);
  289.     (void) dup2(0, 1);
  290.     (void) dup2(0, 2);
  291.     c = open("/dev/tty", O_RDWR);
  292.     if (c >= 0) {
  293.         ioctl(c, TIOCNOTTY, (char *)0);
  294.         (void) close(c);
  295.     }
  296. #ifdef LOG_DAEMON
  297.     openlog("gdpd", LOG_PID, LOG_DAEMON);
  298. #else
  299.     openlog("gdpd", LOG_PID);
  300. #endif
  301.     }
  302.  
  303.     /*
  304.      * Get listener socket
  305.      */
  306.     if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
  307.     syslog(LOG_ERR, "socket: %m");
  308.     exit(1);
  309.     }
  310.  
  311. #ifdef SO_BROADCAST
  312.     if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &on, sizeof (on)) < 0) {
  313.     syslog(LOG_ERR, "setsockopt: %m");
  314.     exit(1);
  315.     }
  316. #endif
  317.  
  318.     /*
  319.      * Get port we need to pay attention to
  320.      */
  321.     bzero((caddr_t)&from, sizeof(from));
  322.     from.sin_family = AF_INET;
  323.     from.sin_addr.s_addr = INADDR_ANY;
  324.     sp = getservbyname("gdp", "udp");
  325.     if (sp == NULL)
  326.     from.sin_port = htons(GDP_PORT);
  327.     else
  328.     from.sin_port = htons(sp->s_port);
  329.  
  330.     if (bind(s, &from, sizeof(from)) < 0) {
  331.     syslog(LOG_ERR, "bind: %m");
  332.     exit(1);
  333.     }
  334.  
  335.     build_iflist();
  336.     send_query(bip);
  337.     signal(SIGALRM, timer);
  338.     timer();
  339.  
  340.     /*
  341.      * Now do the work
  342.      */
  343.  
  344.     for (;;) {
  345.     fromlen = sizeof(from);
  346.     c = recvfrom(s, buf, sizeof(buf), 0, (caddr_t)&from, &fromlen);
  347.     if (c <= 0) {
  348.         if (errno == EINTR)
  349.         continue;
  350.         syslog(LOG_ERR, "recvfrom: %m");
  351.         exit(1);
  352.     }
  353.     gdp = (struct gdppkt *)buf;
  354.     if (gdp->version != GDP_VERSION)
  355.         continue;
  356.     if (debug) {
  357.         hp = gethostbyaddr(&from.sin_addr, sizeof(struct in_addr),
  358.         AF_INET);
  359.         syslog(LOG_DEBUG, "%s received from %s", (gdp->code == GDP_REPORT
  360.         ? "REPORT" : (gdp->code == GDP_QUERY ? "QUERY" : "UNKNOWN")),
  361.         hp ? hp->h_name : (char *)inet_ntoa(from.sin_addr));
  362.     }
  363.  
  364.     oldmask = sigblock(sigmask(SIGALRM));
  365.     switch (gdp->code) {
  366.     case GDP_REPORT:
  367.         if (report_time == 0)
  368.         process_report(&from, gdp);
  369.         break;
  370.     case GDP_QUERY:
  371.         if (report_time != 0)
  372.         process_query(&from, gdp);
  373.         break;
  374.     default:
  375.         break;
  376.     }
  377.     sigsetmask(oldmask);
  378.     }
  379. }
  380.  
  381. /*
  382.  * find_neighbor
  383.  * Look for a given neighbor in the list and return ptr or NULL
  384.  */
  385.  
  386. struct neighbor *find_neighbor (nt, ip)
  387.     struct neighbor **nt;
  388.     struct in_addr ip;
  389. {
  390.     struct neighbor *p;
  391.  
  392.     for (p = *nt; p != NULL; p = p->next)
  393.     if (p->ip.s_addr == ip.s_addr)
  394.         break;
  395.     return(p);
  396. }
  397.  
  398. /*
  399.  * enter_neighbor
  400.  * Enter a new neighbor into the table in priority order
  401.  */
  402.  
  403. enter_neighbor (nt, ag)
  404.     struct neighbor **nt;
  405.     struct addrgrp *ag;
  406. {
  407.     struct neighbor *p, *pp, *newp;
  408.  
  409.     newp = (struct neighbor *)malloc(sizeof(struct neighbor));
  410.     if (newp == NULL)
  411.     return;
  412.  
  413.     newp->ip = ag->ip;
  414.     newp->priority = ntohs(ag->priority);
  415.     newp->holdtime = ntohs(ag->holdtime);
  416.     newp->next = NULL;
  417.     for (p = pp = *nt; p != NULL; pp = p, p = p->next)
  418.     if (newp->priority > p->priority)
  419.         break;
  420.     if (p == NULL) {
  421.     if (*nt == NULL)
  422.         *nt = newp;
  423.     else
  424.         pp->next = newp;
  425.     } else if (p == pp) {
  426.     newp->next = *nt;
  427.     *nt = newp;
  428.     } else {
  429.     pp->next = newp;
  430.     newp->next = p;
  431.     }
  432. }
  433.  
  434. /*
  435.  * delete_neighbor
  436.  * Remove neighbor from the list
  437.  */
  438.  
  439. delete_neighbor (nt, dp)
  440.     struct neighbor **nt;
  441.     struct neighbor *dp;
  442. {
  443.     struct neighbor *p, *pp;
  444.  
  445.     for (p = pp = *nt; p != NULL; pp = p, p = p->next)
  446.     if (p == dp)
  447.         break;
  448.     if (p == pp)
  449.     *nt = p->next;
  450.     else
  451.     pp->next = p->next;
  452.     free(p);
  453.  
  454. }
  455.  
  456. /*
  457.  * robin_neighbor
  458.  * Perform round robin on received neighbors of equal priority
  459.  */
  460.  
  461. robin_neighbor ()
  462. {
  463.     struct neighbor *p, *pp;
  464.  
  465.     /*
  466.      * Find where next lower priorty starts
  467.      */
  468.     for (p = pp = rcvd_neighbors; p != NULL; p = p->next)
  469.     if (default_neighbor->priority > p->priority)
  470.         break;
  471.     /*
  472.      * If there is only a single entry, then don't bother
  473.      */
  474.     if (default_neighbor == pp)
  475.     return;
  476.  
  477.     /*
  478.      * Splice old one at end of equal priority list
  479.      */
  480.     rcvd_neighbors = default_neighbor->next;
  481.     pp->next = default_neighbor;
  482.     default_neighbor->next = p;
  483.     update_routes();
  484. }
  485.  
  486. /*
  487.  * process_report
  488.  * handle processing of GDP report messages
  489.  */
  490.  
  491. process_report (from, gdp)
  492.     struct sockaddr_in *from;
  493.     struct gdppkt *gdp;
  494. {
  495.     struct neighbor *p;
  496.     struct addrgrp *a;
  497.  
  498.     a = gdp->addrs;
  499.     while (gdp->count-- > 0) {
  500.     if (valid_address(a->ip)) {
  501.         p = find_neighbor(&sent_neighbors, a->ip);
  502.         if (p != NULL)
  503.         p->holdtime = ntohs(a->holdtime);
  504.         p = find_neighbor(&rcvd_neighbors, a->ip);
  505.         if (p == NULL || p->priority != ntohs(a->priority)) {
  506.         if (p != NULL) {
  507.             if (flush)
  508.             flush_routes(p->ip);
  509.             delete_neighbor(&rcvd_neighbors, p);
  510.         }
  511.         enter_neighbor(&rcvd_neighbors, a);
  512.         update_routes();
  513.         round = round_robin;        /* restart timer */
  514.         } else
  515.         p->holdtime = ntohs(a->holdtime);
  516.     } else if (debug)
  517.         syslog(LOG_DEBUG, "invalid IP address: %s",
  518.         inet_ntoa(a->ip));
  519.     a++;
  520.     }
  521. }
  522.  
  523. /*
  524.  * process_query
  525.  * Process a QUERY and return a REPORT
  526.  */
  527.  
  528. process_query (from, gdp)
  529.     struct sockaddr_in *from;
  530.     struct gdppkt *gdp;
  531. {
  532. }
  533.  
  534. /*
  535.  * timer
  536.  * Wake up once in a while and process running timers, etc.
  537.  */
  538.  
  539. timer ()
  540. {
  541.     struct neighbor *p, *dp;
  542.     struct in_addr bip;
  543.  
  544.     bip.s_addr = 0L;
  545.     if (report_time != 0) {
  546.     if (report <= 0) {
  547.         send_report(bip);
  548.         report = report_time;
  549.     } else
  550.         report -= ALARM_INTERVAL;
  551.     } else {
  552.     if (query_time != 0) {
  553.         query -= ALARM_INTERVAL;
  554.         if (query <= 0) {
  555.         for (p = sent_neighbors; p != NULL; p = p->next)
  556.             send_query(p->ip);
  557.         query = query_time;
  558.         }
  559.     }
  560.     for (p = rcvd_neighbors; p != NULL; ) {
  561.         dp = p;
  562.         p = p->next;
  563.         dp->holdtime -= ALARM_INTERVAL;
  564.         if (dp->holdtime <= 0) {
  565.         if (flush)
  566.             flush_routes(dp->ip);
  567.         delete_neighbor(&rcvd_neighbors, dp);
  568.         update_routes();
  569.         round = round_robin;        /* restart timer */
  570.         }
  571.     }
  572.     }
  573.     if (round_robin != 0) {
  574.     round -= ALARM_INTERVAL;
  575.     if (round <= 0) {
  576.         if (default_neighbor != NULL)
  577.         robin_neighbor();
  578.         round = round_robin;
  579.     }
  580.     }
  581.     alarm(ALARM_INTERVAL);
  582. }
  583.  
  584. /*
  585.  * send_query
  586.  * Send a GDP query message
  587.  */
  588.  
  589. send_query (ip)
  590.     struct in_addr ip;
  591. {
  592.     struct gdppkt gdp;
  593.     struct sockaddr_in sin;
  594.     struct iface *ifp;
  595.     struct neighbor *p;
  596.  
  597.     bzero(&gdp, sizeof(gdp));
  598.     gdp.version = GDP_VERSION;
  599.     gdp.code = GDP_QUERY;
  600.     bzero(&sin, sizeof(sin));
  601.     sin.sin_family = AF_INET;
  602.     sin.sin_addr = ip;
  603.     if (sp == NULL)
  604.     sin.sin_port = htons(GDP_PORT);
  605.     else
  606.     sin.sin_port = htons(sp->s_port);
  607.     if (ip.s_addr == 0L) {
  608.     for (ifp = iflist; ifp != NULL; ifp = ifp->next) {
  609.         if ((ifp->flags & IFF_BROADCAST) == 0)
  610.         continue;
  611.         sin.sin_addr = ifp->ipbroadcast;
  612.         (void) sendto(s, &gdp, sizeof(gdp) - sizeof(struct addrgrp), 0,
  613.         &sin, sizeof(sin));
  614.     }
  615.     for (p = sent_neighbors; p != NULL; p = p->next)
  616.         send_query(p->ip);
  617.     } else
  618.     (void) sendto(s, &gdp, sizeof(gdp) - sizeof(struct addrgrp), 0,
  619.         &sin, sizeof(sin));
  620. }
  621.  
  622. /*
  623.  * send_report
  624.  * Send a GDP REPORT message
  625.  */
  626.  
  627. send_report (ip)
  628.     struct in_addr ip;
  629. {
  630. }
  631.  
  632. /*
  633.  * build_iflist
  634.  * Build a list of interfaces and accompaning information
  635.  */
  636.  
  637. build_iflist ()
  638. {
  639.     int n;
  640.     char ifbuf[BUFSIZ];
  641.     struct ifconf ifc;
  642.     struct ifreq *ifr, ifreq;
  643.     struct iface *ifp;
  644.     struct sockaddr_in *sa;
  645.     short flags;
  646.  
  647.     ifc.ifc_len = sizeof(ifbuf);
  648.     ifc.ifc_buf = ifbuf;
  649.     if (ioctl(s, SIOCGIFCONF, &ifc) < 0) {
  650.     syslog(LOG_ERR, "ioctl(IFCONF): %m");
  651.     exit(1);
  652.     }
  653.     ifr = ifc.ifc_req;
  654.     for (n = ifc.ifc_len / sizeof(struct ifreq); n > 0; n--, ifr++) {
  655.     /*
  656.      * Ignore the loopback interface
  657.      */
  658.     if (strncmp(ifr->ifr_name, "lo", 2) == 0)
  659.         continue;
  660.     /*
  661.      * Ignore all interfaces which aren't running
  662.      */
  663.     strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name));
  664.     if (ioctl(s, SIOCGIFFLAGS, &ifreq) < 0)
  665.         continue;
  666.     else
  667.         flags = ifreq.ifr_flags;
  668.     if ((flags & IFF_RUNNING) == 0)
  669.         continue;
  670.     sa = (struct sockaddr_in *)&ifr->ifr_addr;
  671.     /*
  672.      * Ignore non-internet family and 0.0.0.0
  673.      */
  674.     if (sa->sin_family != AF_INET || sa->sin_addr.s_addr == 0L)
  675.         continue;
  676.     ifp = (struct iface *)malloc(sizeof(struct iface));
  677.     if (ifp == NULL)
  678.         break;
  679.     bzero(ifp, sizeof(struct iface));
  680.     strncpy(ifp->name, ifr->ifr_name, sizeof(ifp->name));
  681.     ifp->ipaddress = sa->sin_addr;
  682.     ifp->flags = flags;
  683.     strncpy(ifreq.ifr_name, ifp->name, sizeof(ifp->name));
  684.     if (ioctl(s, SIOCGIFNETMASK, &ifreq) >= 0) {
  685.         sa = (struct sockaddr_in *)&ifreq.ifr_addr;
  686.         ifp->ipmask = sa->sin_addr;
  687.     }
  688.     if (ifp->flags & IFF_BROADCAST) {
  689.         strncpy(ifreq.ifr_name, ifp->name, sizeof(ifp->name));
  690.         if (ioctl(s, SIOCGIFBRDADDR, &ifreq) >= 0) {
  691.         sa = (struct sockaddr_in *)&ifreq.ifr_addr;
  692.         ifp->ipbroadcast = sa->sin_addr;
  693.         }
  694.     }
  695.     if (iflist == NULL)
  696.         iflist = ifp;
  697.     else {
  698.         ifp->next = iflist;
  699.         iflist = ifp;
  700.     }
  701.     }
  702. }
  703.  
  704. /*
  705.  * valid_address
  706.  * Determine if give IP address is something we grok.
  707.  */
  708.  
  709. valid_address (ip)
  710.     struct in_addr ip;
  711. {
  712.     struct iface *ifp;
  713.  
  714.     for (ifp = iflist; ifp != NULL; ifp = ifp->next) {
  715.     if ((ip.s_addr & ifp->ipmask.s_addr) ==
  716.         (ifp->ipaddress.s_addr & ifp->ipmask.s_addr))
  717.         return(1);
  718.     }
  719.     return(0);
  720. }
  721.  
  722. /*
  723.  * update_routes
  724.  * Update default route if necessary when something changes
  725.  */
  726.  
  727. update_routes ()
  728. {
  729.     struct rtentry rt;
  730.     struct sockaddr_in *sa;
  731.     struct in_addr inet_makeaddr();
  732.  
  733.     if (default_neighbor == rcvd_neighbors)
  734.     return;
  735.  
  736.     bzero(&rt, sizeof(rt));
  737.     rt.rt_flags = RTF_UP;
  738.     if (metric > 0)
  739.     rt.rt_flags |= RTF_GATEWAY;
  740.     sa = (struct sockaddr_in *)&rt.rt_dst;
  741.     sa->sin_family = AF_INET;
  742.     sa->sin_addr = inet_makeaddr(0, INADDR_ANY);
  743.     sa = (struct sockaddr_in *)&rt.rt_gateway;
  744.     sa->sin_family = AF_INET;
  745.     if (default_neighbor != NULL) {
  746.     sa->sin_addr = default_neighbor->ip;
  747.     if (metric == 0)
  748.         flush_arp();
  749.     if (logging)
  750.         syslog(LOG_NOTICE, "deleting old default: %s",
  751.         inet_ntoa(sa->sin_addr));
  752.     if (!debug)
  753.         (void) ioctl(s, SIOCDELRT, &rt);
  754.     }
  755.     default_neighbor = rcvd_neighbors;
  756.     if (default_neighbor == NULL)
  757.     return;
  758.     sa->sin_addr = default_neighbor->ip;
  759.     if (logging)
  760.     syslog(LOG_NOTICE, "adding new default: %s",
  761.         inet_ntoa(sa->sin_addr));
  762.     if (!debug)
  763.     (void) ioctl(s, SIOCADDRT, &rt);
  764. }
  765.  
  766. /*
  767.  * flush_arp
  768.  * Flush the ARP tables. Used when we delete a default route and metric
  769.  * is zero.
  770.  */
  771.  
  772. flush_arp ()
  773. {
  774.     int size, fd;
  775.     int arptab_size;
  776.     struct arptab *atp;
  777.     struct arptab *at;
  778.     struct arpreq ar;
  779.     struct sockaddr_in *sa;
  780.  
  781.     if (logging)
  782.     syslog(LOG_NOTICE, "flushing ARP tables");
  783.     if (debug)
  784.     return;
  785.     fd = open(MEM, O_RDONLY);
  786.     if (fd < 0) {
  787.     syslog(LOG_ERR,"%s: cannot open", MEM);
  788.     exit(1);
  789.     }
  790.  
  791.     if (lseek(fd, (long)nl[X_ARPTAB_SIZE].n_value, 0) == -1 ||
  792.     read(fd, &arptab_size, sizeof(arptab_size)) != sizeof(arptab_size) ||
  793.     arptab_size < 0 || arptab_size > 10000) {
  794.     syslog(LOG_ERR, "bad ARP namelist");
  795.     exit(1);
  796.     }
  797.     size = arptab_size * sizeof(struct arptab);
  798.     atp = (struct arptab *)malloc(size);
  799.     at = atp;
  800.     if (at == NULL) {
  801.     close(fd);
  802.     return;
  803.     }
  804.  
  805.     if (lseek(fd, (long)nl[X_ARPTAB].n_value, 0) == -1 ||
  806.     read(fd, (char *)at, size) != size) {
  807.     syslog(LOG_ERR, "error reading ARP table %m");
  808.     exit(1);
  809.     }
  810.     bzero(&ar, sizeof(ar));
  811.     sa = (struct sockaddr_in *)&ar.arp_pa;
  812.     sa->sin_family = AF_INET;
  813.     for ( ; arptab_size-- > 0; at++) {
  814. #ifndef pyr
  815.     if (at->at_iaddr.s_addr == 0 || at->at_flags == 0)
  816. #else
  817.     struct sockaddr_in sin;
  818.  
  819.     bcopy(&at->at_addr, &sin, sizeof(struct sockaddr_in));
  820.     if (sin.sin_addr.s_addr == 0 || at->at_flags == 0)
  821. #endif
  822.         continue;
  823.     if (at->at_flags & ATF_PERM)
  824.         continue;
  825. #ifndef pyr
  826.     sa->sin_addr = at->at_iaddr;
  827. #else
  828.     sa->sin_addr = sin.sin_addr;
  829. #endif
  830.     (void) ioctl(s, SIOCDARP, &ar);
  831.     }
  832.     close(fd);
  833.     free(atp);
  834. }
  835.  
  836. /*
  837.  * flush_routes
  838.  * Flush the routing table. We do this when asked.
  839.  */
  840.  
  841. flush_routes (ip)
  842.     struct in_addr ip;
  843. {
  844.     struct in_addr gwin, dstin;
  845.     struct mbuf mb;
  846.     register struct rtentry *rt;
  847.     register struct mbuf *mbp;
  848.     struct mbuf **routehash;
  849.     int rthashsize, i, doinghost = 1, fd;
  850.  
  851.     fd = open(MEM, O_RDONLY);
  852.     if (fd < 0) {
  853.     syslog(LOG_ERR,"%s: cannot open", MEM);
  854.     exit(1);
  855.     }
  856.  
  857.     if (lseek(fd, nl[N_RTHASHSIZE].n_value, 0) == -1 ||
  858.     read(fd, &rthashsize, sizeof (rthashsize)) != sizeof(rthashsize)) {
  859.     syslog(LOG_ERR, "bad ROUTE namelist");
  860.     exit(1);
  861.     }
  862.     if (logging)
  863.     syslog(LOG_NOTICE, "flushing routes via %s", inet_ntoa(ip));
  864.     routehash = (struct mbuf **)malloc(rthashsize*sizeof (struct mbuf *));
  865.     if (routehash == NULL) {
  866.     close(fd);
  867.     return;
  868.     }
  869.     if (lseek(fd, nl[N_RTHOST].n_value, 0) == -1 ||
  870.     read(fd, routehash, rthashsize*sizeof (struct mbuf *)) !=
  871.     rthashsize*sizeof(struct mbuf *)) {
  872.     syslog(LOG_ERR, "error reading ROUTE table %m");
  873.     exit(1);
  874.     }
  875. again:
  876.     for (i = 0; i < rthashsize; i++) {
  877.     if (routehash[i] == 0)
  878.         continue;
  879.     mbp = routehash[i];
  880.         while (mbp) {
  881.         if (lseek(fd, mbp, 0) == -1 ||
  882.             read(fd, &mb, sizeof (mb)) != sizeof(mb))
  883.             goto done;
  884.         rt = mtod(&mb, struct rtentry *);
  885.         if ((rt->rt_flags & RTF_GATEWAY) &&
  886.             rt->rt_gateway.sa_family == AF_INET) {
  887.             gwin = ((struct sockaddr_in *)&rt->rt_gateway)->sin_addr;
  888.             dstin = ((struct sockaddr_in *)&rt->rt_dst)->sin_addr;
  889.             /*
  890.              * Flush all routes through this device except
  891.              * default which is done later.
  892.              */
  893.             if (gwin.s_addr == ip.s_addr && dstin.s_addr != 0L) {
  894.             if (logging) {
  895.                 syslog(LOG_NOTICE, "flushing route %s",
  896.                 inet_ntoa(dstin));
  897.             }
  898.             if (!debug)
  899.                 (void) ioctl(s, SIOCDELRT, (caddr_t)rt);
  900.             }
  901.         }
  902.         mbp = mb.m_next;
  903.         }
  904.     }
  905.     if (doinghost) {
  906.     if (lseek(fd, nl[N_RTNET].n_value, 0) == -1 ||
  907.         read(fd, routehash, rthashsize*sizeof (struct mbuf *)) !=
  908.         rthashsize*sizeof(struct mbuf *))
  909.         goto done;
  910.     doinghost = 0;
  911.     goto again;
  912.     }
  913. done:
  914.     free(routehash);
  915.     close(fd);
  916. }
  917.